<?php

namespace app\common\library;


use app\admin\model\Reserve;
use app\admin\model\Setting;
use app\common\model\Room;
use Carbon\Carbon;
use fast\Random;
use think\Env;
use think\Log;

/**
 * 日志记录类
 */
class Yunding
{

    public function isElemeterSwitchOn($homeId, $uuid)
    {
        $clientId = Env::get('yunding.client_id');
        $clientSecret = Env::get('yunding.client_secret');
        $domain = Env::get('yunding.domain');

        $yundingAccesstoken = Setting::where('name', 'yunding_accesstoken')->find();
        $yundingExpirestime = Setting::where('name', 'yunding_expires_time')->find();

        if (empty($yundingAccesstoken->value) or empty($yundingExpirestime->value)
            or $yundingExpirestime->value < time() + 3600 * 24 * 2) {

            $url = $domain . '/access_token';

            $postdata = json_encode([
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
            ]);

            $returnData = $this->curl_post($url, $postdata);
            if (0 == $returnData['ErrNo']) {
                $yundingAccesstoken->value = $returnData['access_token'];
                $yundingExpirestime->value = $returnData['expires_time'];

                $yundingAccesstoken->save();
                $yundingExpirestime->save();
            } else {
                return false;
            }
        }

        $url = $domain . '/get_elemeter_info';
        $url = $url . '?access_token=' . $yundingAccesstoken->value . '&home_id=' . $homeId . '&uuid=' . $uuid;

        $returnData = $this->curl_get($url);

        if (0 == $returnData['ErrNo']) {
            if (isset($returnData['enable_state']) and 1 == $returnData['enable_state']) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public function elemeterSwitchOn($homeId, $uuid)
    {
        $clientId = Env::get('yunding.client_id');
        $clientSecret = Env::get('yunding.client_secret');
        $domain = Env::get('yunding.domain');

        $yundingAccesstoken = Setting::where('name', 'yunding_accesstoken')->find();
        $yundingExpirestime = Setting::where('name', 'yunding_expires_time')->find();

        if (empty($yundingAccesstoken->value) or empty($yundingExpirestime->value)
            or $yundingExpirestime->value < time() + 3600 * 24 * 2) {

            $url = $domain . '/access_token';

            $postdata = json_encode([
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
            ]);

            $returnData = $this->curl_post($url, $postdata);
            if (0 == $returnData['ErrNo']) {
                $yundingAccesstoken->value = $returnData['access_token'];
                $yundingExpirestime->value = $returnData['expires_time'];

                $yundingAccesstoken->save();
                $yundingExpirestime->save();
            } else {
                return false;
            }
        }

        $url = $domain . '/elemeter_switch_on';

        $postdata = json_encode([
            'access_token' => $yundingAccesstoken->value,
            'home_id' => $homeId,
            'uuid' => $uuid,
        ]);


        $returnData = $this->curl_post($url, $postdata);

        if (0 == $returnData['ErrNo']) {
            return true;
        } else {
            return false;
        }

    }

    public function elemeterSwitchOff($homeId, $uuid)
    {
        $clientId = Env::get('yunding.client_id');
        $clientSecret = Env::get('yunding.client_secret');
        $domain = Env::get('yunding.domain');

        $yundingAccesstoken = Setting::where('name', 'yunding_accesstoken')->find();
        $yundingExpirestime = Setting::where('name', 'yunding_expires_time')->find();

        if (empty($yundingAccesstoken->value) or empty($yundingExpirestime->value)
            or $yundingExpirestime->value < time() + 3600 * 24 * 2) {

            $url = $domain . '/access_token';

            $postdata = json_encode([
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
            ]);

            $returnData = $this->curl_post($url, $postdata);
            if (0 == $returnData['ErrNo']) {
                $yundingAccesstoken->value = $returnData['access_token'];
                $yundingExpirestime->value = $returnData['expires_time'];

                $yundingAccesstoken->save();
                $yundingExpirestime->save();
            } else {
                return false;
            }
        }

        $url = $domain . '/elemeter_switch_off';

        $postdata = json_encode([
            'access_token' => $yundingAccesstoken->value,
            'home_id' => $homeId,
            'uuid' => $uuid,
        ]);


        $returnData = $this->curl_post($url, $postdata);

        if (0 == $returnData['ErrNo']) {
            return true;
        } else {
            return false;
        }

    }


    public function deletePassword($homeId, $uuid, $passwordId)
    {
        // 当没有passwordId时，是还没有向第三方下发密码的预约，直接返回true
        if (empty($passwordId)) {
            return true;
        }

        $clientId = Env::get('yunding.client_id');
        $clientSecret = Env::get('yunding.client_secret');
        $domain = Env::get('yunding.domain');

        $yundingAccesstoken = Setting::where('name', 'yunding_accesstoken')->find();
        $yundingExpirestime = Setting::where('name', 'yunding_expires_time')->find();

        if (empty($yundingAccesstoken->value) or empty($yundingExpirestime->value)
            or $yundingExpirestime->value < time() + 3600 * 24 * 2) {

            $url = $domain . '/access_token';

            $postdata = json_encode([
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
            ]);

            $returnData = $this->curl_post($url, $postdata);
            if (0 == $returnData['ErrNo']) {
                $yundingAccesstoken->value = $returnData['access_token'];
                $yundingExpirestime->value = $returnData['expires_time'];

                $yundingAccesstoken->save();
                $yundingExpirestime->save();
            } else {
                return false;
            }
        }

        $url = $domain . '/delete_password';

        $postdata = json_encode([
            'access_token' => $yundingAccesstoken->value,
            'home_id' => $homeId,
            'uuid' => $uuid,
            'password_id' => $passwordId,
        ]);


        $returnData = $this->curl_post($url, $postdata);

        if (0 == $returnData['ErrNo']) {
            return true;
        } else {
            return false;
        }
    }

    public function addPassword($homeId, $uuid, $phoneNumber, $starttime, $endtime)
    {
        //如果预约是2天后的预约，不真实的下发密码
        if (Carbon::parse($starttime)->getTimestamp() > time() + 3600 * 24 * 2) {
            return ['password' => '暂未生成', 'password_id' => null, 'serviceid' => null];
        }

        $clientId = Env::get('yunding.client_id');
        $clientSecret = Env::get('yunding.client_secret');
        $domain = Env::get('yunding.domain');

        $yundingAccesstoken = Setting::where('name', 'yunding_accesstoken')->find();
        $yundingExpirestime = Setting::where('name', 'yunding_expires_time')->find();

        if (empty($yundingAccesstoken->value) or empty($yundingExpirestime->value)
            or $yundingExpirestime->value < time() + 3600 * 24 * 2) {

            $url = $domain . '/access_token';

            $postdata = json_encode([
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
            ]);

            $returnData = $this->curl_post($url, $postdata);
            if (0 == $returnData['ErrNo']) {
                $yundingAccesstoken->value = $returnData['access_token'];
                $yundingExpirestime->value = $returnData['expires_time'];

                $yundingAccesstoken->save();
                $yundingExpirestime->save();
            } else {
                return false;
            }
        }


        // fix 一个云丁的bug, 当生成的密码和当天的密码有3个数字连续在同一位数，虽然返回的是生成密码成功，但在云丁的平台是添加不成功的

        // 通过uuid和starttime得到当天生成的密码
        $room = Room::where('yunding_uuid', $uuid)->find();
        if (!$room) {
            return false;
        }

        $reserves = Reserve::where('room_id', $room->id)
            ->where('starttime', '>', Carbon::now()->startOfDay()->toDateTimeString())
            ->where('yunding_password_id', 'NEQ', null)
            ->select();

        $passwords = array_map(function ($e) {
            return $e->opendoor_pwd;
        }, $reserves);


        for ($i = 1; $i <= 10; $i++) {
            if (9 == $i) {
//                throw new \Exception("连续${i}次没有生成有效密码");
                return false;
            }
            $password = Random::numeric(6);

            $hasSimilar = array_reduce($passwords, function ($a, $b) use ($password) {
                if ($this->isSimilar($b, $password)) {
                    $a += 1;
                }
                return $a;
            }, 0);

            if ($hasSimilar) {
                continue;
            } else {
                break;
            }
        }

        $url = $domain . '/add_password';

        $postdata = json_encode([
            'access_token' => $yundingAccesstoken->value,
            'home_id' => $homeId,
            'uuid' => $uuid,
            'phonenumber' => $phoneNumber,
            'is_default' => 0,
            'password' => $password,
            'name' => 'test',
            'permission_begin' => Carbon::parse($starttime)->subMinutes(2)->getTimestamp(), // 统一的提前2分钟给密码
            'permission_end' => Carbon::parse($endtime)->getTimestamp(),
        ]);

        $returnData = $this->curl_post($url, $postdata);

        if (0 == $returnData['ErrNo']) {
            return ['password' => $password, 'password_id' => $returnData['id'], 'serviceid' => $returnData['serviceid']];
        } else {
            Log::record($returnData, 'yunding_add_password');
            return false;
        }
    }

    public function searchHomeid($uuid) 
    {
        $homeId = '';
        $domain = Env::get('yunding.domain');
        $accessToken = $this->getAccessToken();

        $url = $domain . '/search_home_info';
        $url = $url . '?access_token=' . $accessToken;

        $returnData = $this->curl_get($url);
        if ($returnData['ErrNo'] == 0) {
            $homeList = $returnData['home_list'];
            foreach ($homeList as $h) {
                $curHomeId = $h['home_id'];
                $devices = $h['devices'];
                foreach ($devices as $d) {
                    if ($uuid == $d['uuid']) {
                        $homeId = $curHomeId;
                        break;
                    }
                }
            }
        }

        return $homeId; 
    }

    //把已有的密码和生成的密码比对，如果接近，重新生成
    private function isSimilar($value1, $value2)
    {
        $cString = '';
        for ($i = 0; $i < strlen($value1); $i++) {
            if ($value1[$i] == $value2[$i]) {
                $cString .= '1';
            } else {
                $cString .= '0';
            }
        }

        if (strstr($cString, '1111')) {
            return true;
        } else {
            return false;
        }
    }

    private function getAccessToken()
    {
        $clientId = Env::get('yunding.client_id');
        $clientSecret = Env::get('yunding.client_secret');
        $domain = Env::get('yunding.domain');

        $yundingAccesstoken = Setting::where('name', 'yunding_accesstoken')->find();
        $yundingExpirestime = Setting::where('name', 'yunding_expires_time')->find();

        if (empty($yundingAccesstoken->value) or empty($yundingExpirestime->value)
            or $yundingExpirestime->value < time() + 3600 * 24 * 2) {

            $url = $domain . '/access_token';

            $postdata = json_encode([
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
            ]);

            $returnData = $this->curl_post($url, $postdata);
            if (0 == $returnData['ErrNo']) {
                $yundingAccesstoken->value = $returnData['access_token'];
                $yundingExpirestime->value = $returnData['expires_time'];

                $yundingAccesstoken->save();
                $yundingExpirestime->save();
            } else {
                return false;
            }
        }

        return $yundingAccesstoken->value;
    
    }

    private function curl_post($url, $postdata)
    {
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检测
        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
            'Expect:'
        )); // 解决数据包大不能提交
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
// curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
        $tmpInfo = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            echo 'Errno' . curl_error($curl);
        }
        curl_close($curl); // 关键CURL会话
        $tmpInfo = json_decode($tmpInfo, true);
        return $tmpInfo;
    }

    //get请求
    private function curl_get($url)
    {
        //初使化curl
        $curl = curl_init();
        //请求的url，由形参传入
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检测
        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
            'Expect:'
        )); // 解决数据包大不能提交
        //将得到的数据返回
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        //不处理头信息
        curl_setopt($curl, CURLOPT_HEADER, 0);
        //连接超过10秒超时
        curl_setopt($curl, CURLOPT_TIMEOUT, 30);
        curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        //执行curl
        $output = curl_exec($curl);
        if (curl_errno($curl)) {
            echo 'Errno' . curl_error($curl);
        }
        //关闭资源
        curl_close($curl);
        //返回内容
        $tmpInfo = json_decode($output, true);
        return $tmpInfo;
    }
}
